#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "voto.h"
#include "entradaSaida.h"
#include "controlador.h"
#include "matriz.h"
#define LEITURA "r"
#define MAX_LINHA 999

void processarEleicao( char *nomeArquivo) {

	FILE *arq;

	abrirArquivo(&arq, nomeArquivo, LEITURA);

	char buffer[MAX_LINHA];

	fgets(buffer, MAX_LINHA, arq);

	int qtdInstancias = atoi(buffer);

	int i = 0;
	for (i = 0; i < qtdInstancias; i++) {

		ListaVoto lv;
		criarListaVoto(&lv);

		fgets(buffer, MAX_LINHA, arq);

		int qtdVotos = atoi(buffer);

		int j = 0;
		int indice = 0;
		for (j = 0; j < qtdVotos; j++) {

			ListaCandidato lc;
			criarListaCandidato(&lc);

			//le o numero de votos
			fgets(buffer, MAX_LINHA, arq);
			int numVotos = atoi(buffer);

			//le a ordem dos candidatos
			fgets(buffer, MAX_LINHA, arq);

			char * pch;
			pch = strtok(buffer, " ");

			indice = 0;
			while (pch != NULL) {
				int candidato = atoi(pch);
				inserirCandidato(&lc,candidato, ++indice);
				pch = strtok(NULL, " ");
			}

			inserirVoto(&lv,numVotos,lc);
		}


		ListaMatriz lm;
		criaListaVazia(&lm);
		gerarMatriz(&lm,lv, indice);

		calcularResultado(lm, indice);


		liberaMatriz(lm);
		liberaVoto(lv);

	}

	fecharArquivo(&arq);
}



void calcularResultado(ListaMatriz LM, int numCandidatos) {

	ListaCandidato vencedores;
	ListaCandidato perdedores;

	criarListaCandidato(&vencedores);
	criarListaCandidato(&perdedores);

	int totalVotos = somaVotos(LM);

	gerarVencedoresPerdedores(&vencedores, &perdedores, LM);

	ListaOcorrencia lo;
	criaListaOcorrenciaVazia(&lo);


	PCandidato aux = vencedores.Primeiro->prox;
	while (aux != NULL)
	{
		inserirItemOcorrenciaPeloCandidato(&lo,aux->itemCandidato.candidato,1);
		aux = aux->prox;
	}

	aux = perdedores.Primeiro->prox;
	while (aux != NULL)
	{
		inserirItemOcorrenciaPeloCandidato(&lo,aux->itemCandidato.candidato,0);
		aux = aux->prox;
	}


	//ordenar ItemOcorrencia e imprimir
	int * ordenado;
	ordenado = ordenar(lo,numCandidatos, 1);

	liberaOcorrencia(lo);

	/*impressao do resultado da eleicao*/

	int i;
	for (i = numCandidatos - 1; i >= 0; i--) {
		printf("%d ", ordenado[i]);
	}

	printf("%d\n", totalVotos);

	/*fim da impressao do resultado*/


}

void gerarVencedoresPerdedores(ListaCandidato *vencedores, ListaCandidato *perdedores, ListaMatriz LM) {

	PMatriz aux = LM.Primeiro->prox;
	while (aux != NULL)
	{
		int v1 = aux->itemMatriz.v1;
		int v2 = aux->itemMatriz.v2;
		int c1 = aux->itemMatriz.primeiro;
		int c2 = aux->itemMatriz.segundo;

		if(v1 > v2) {
			inserirCandidato(vencedores,c1,1);
			inserirCandidato(perdedores,c2,1);
		} else if (v1 < v2) {
			inserirCandidato(vencedores,c2,1);
			inserirCandidato(perdedores,c1,1);
		} else {
			if (c1 < c2) {
				inserirCandidato(vencedores,c1,1);
				inserirCandidato(perdedores,c2,1);
			} else {
				inserirCandidato(vencedores,c2,1);
				inserirCandidato(perdedores,c1,1);
			}
		}

		aux = aux->prox;
	}
}

int somaVotos(ListaMatriz L)
{
	PMatriz aux = L.Primeiro->prox;
	int somatorio = 0;
	while (aux != NULL)
	{
		int primeiroValor = aux->itemMatriz.v1;
		int segundoValor = aux->itemMatriz.v2;

		if (primeiroValor > segundoValor) {
			somatorio += primeiroValor;
		} else {
			somatorio += segundoValor;
		}

		aux = aux->prox;
	}
	return somatorio;
}


int isListaOcorrenciaVazia(ListaOcorrencia L) {
	return (L.Primeiro->prox == NULL);
}

void criaListaOcorrenciaVazia(ListaOcorrencia *L) {
	L->Primeiro = (POcorrencia)malloc(sizeof(Ocorrencia));
	L->Ultimo = (POcorrencia)malloc(sizeof(Ocorrencia));
	L->Primeiro->prox = NULL;
	L->Ultimo->prox = NULL;
}

void inserirPonteiroOcorrencia(ListaOcorrencia *L, POcorrencia P) {
	if(isListaOcorrenciaVazia(*L))
		L->Primeiro->prox = P;
	else
	{
		L->Ultimo->prox->prox = P;
	}
	L->Ultimo->prox = P;
	P->prox = NULL;
}

void inserirItemOcorrenciaPeloCandidato(ListaOcorrencia *L, int candidato, int vencedor) {

	int insere = 0;

	POcorrencia p = encontrarOcorrencia(L,candidato);
	ItemOcorrencia item;

	if(p == NULL) {

		p = (POcorrencia)malloc(sizeof(Ocorrencia));

		item.candidato = candidato;
		item.p1 = vencedor == 1;
		item.p2 = vencedor == 0;

		p->itemOcorrencia = item;

		insere = 1;

	} else {

		if(vencedor) {
			p->itemOcorrencia.p1 = p->itemOcorrencia.p1 + 1;
		} else {
			p->itemOcorrencia.p2 = p->itemOcorrencia.p2 + 1;
		}

	}



	if(insere) {
		inserirPonteiroOcorrencia(L,p);
	}

}

void inserirItemOcorrencia(ListaOcorrencia *L, int candidato, int p1, int p2) {

	POcorrencia a = (POcorrencia)malloc(sizeof(Ocorrencia));
	ItemOcorrencia item;
	item.candidato = candidato;
	item.p1 = p1;
	item.p2 = p2;

	a->itemOcorrencia = item;

	inserirPonteiroOcorrencia(L,a);
}

POcorrencia encontrarOcorrencia(ListaOcorrencia *L, int candidato) {



	POcorrencia item = NULL;

	POcorrencia aux = L->Primeiro;
	while (aux != NULL)
	{

		if(aux->itemOcorrencia.candidato == candidato) {
			item = aux;
			break;
		}

		aux = aux->prox;
	}

	return item;
}

int *ordenar(ListaOcorrencia L, int tam, int boolean) {

	int *vetor = (int*)malloc(tam*sizeof(int));
	ItemOcorrencia x;

	int indiceVetor = 0;
	POcorrencia aux = L.Primeiro->prox;
	while (aux != NULL)
	{
		vetor[indiceVetor] = aux->itemOcorrencia.candidato;
		aux = aux->prox;
		indiceVetor++;
	}


	int i, j;
	i = 0;
	for (j=1;j<tam;j++)
	{
	  POcorrencia ocorrencia = encontrarOcorrencia(&L,vetor[j]);
	  x = ocorrencia->itemOcorrencia;

	  i = j - 1;
	  POcorrencia ocorrencia2 = encontrarOcorrencia(&L, vetor[i]);
	  ItemOcorrencia item = ocorrencia2->itemOcorrencia;

	  //int maior = comparar(item,x);

			  /*(item.p1 > x.p1);

	  if(item.p1 == x.p1) {
		  maior = (item.p2 > x.p2);

		  if(item.p2 == x.p2) {
			  maior = item.candidato < x.candidato;
		  } else {
			  maior = 1;
		  }
	  }*/


	  while((i >=0) && comparar(item,x)) {

		  vetor[i+1] = item.candidato;
		  i = i -1;

		  if (i >= 0) {
			  ocorrencia2 = encontrarOcorrencia(&L, vetor[i]);
			  item = ocorrencia2->itemOcorrencia;
		  }

	  }
	  /*for ( i = j -1; i >= 0 && maior; i --)
		  vetor[i+1] = vetor[i];*/

	  //ocorrencia = encontrarOcorrencia(&L, vetor[i]);

	  vetor[i+1] = x.candidato;
	}

	return vetor;

}

int comparar(ItemOcorrencia primeiro, ItemOcorrencia segundo) {

	int maior = (primeiro.p1 > segundo.p1);

	if(primeiro.p1 == segundo.p1) {
	  maior = (primeiro.p2 > segundo.p2);

	  if(primeiro.p2 == segundo.p2) {
		  maior = primeiro.candidato > segundo.candidato;
	  } else {
		  maior = 1;
	  }
	}
	return maior;
}

void gerarMatriz(ListaMatriz *LM, ListaVoto LV, int numCandidatos) {

	int * produto = gerarCombinacoes(LV.Primeiro->prox->itemVoto.candidatos, numCandidatos);
	int tamanhoProduto = numCandidatos * (numCandidatos - 1);
	int i;
	for(i = 0; i < (tamanhoProduto / 2); i++) {
		int p1 = produto[i];
		int p2 = produto[tamanhoProduto - i - 1];
		int v1 = 0;
		int v2 = 0;
		int indice1, indice2;

		PVoto votoAux = LV.Primeiro->prox;
		while (votoAux != NULL)
		{

			ListaCandidato LC = votoAux->itemVoto.candidatos;
			PCandidato candAux = LC.Primeiro->prox;
			while (candAux != NULL)
			{
				if(candAux->itemCandidato.candidato == p1) {
					indice1 = candAux->itemCandidato.indice;
				}
				if(candAux->itemCandidato.candidato == p2) {
					indice2 = candAux->itemCandidato.indice;
				}

				candAux = candAux->prox;
			}

			if (indice1 < indice2) {
				v1 +=  votoAux->itemVoto.votos;
			} else if (indice1 > indice2) {
				v2 +=  votoAux->itemVoto.votos;
			} else if (p1 <= p2) {
				v1 +=  votoAux->itemVoto.votos;
			} else {
				v2 +=  votoAux->itemVoto.votos;
			}

			votoAux = votoAux->prox;

		}
		inserirItemMatriz(LM,p1,p2,v1,v2);
	}

}


int * gerarCombinacoes(ListaCandidato L, int num) {


	int totalCombinacoes = (num * (num-1));

	int *produto = (int*)malloc(totalCombinacoes*sizeof(int));

	int vetor[num];

	int i = 0;
	PCandidato aux = L.Primeiro->prox;
	while (aux != NULL)
	{
		vetor[i++] = aux->itemCandidato.candidato;
		aux = aux->prox;
	}

	int j=0;
	int indiceProduto = 0;
	for (i = 0; i < num; i++ ) {
		for (j = i + 1 ; j < num; j ++) {
			produto[indiceProduto] = vetor[i];
			produto[totalCombinacoes - indiceProduto - 1] = vetor[j];
			indiceProduto++;
		}

	}

	return produto;

}

void liberaOcorrencia(ListaOcorrencia L) {

	POcorrencia p = L.Primeiro->prox;
	while (p != NULL) {
		POcorrencia t = p->prox;
		free(p);
		p = t;
	}
}
